package com.lagou.edu.factory;

import com.lagou.edu.annotition.MyAutowired;
import com.lagou.edu.annotition.MyComponent;
import com.lagou.edu.annotition.MyTransactional;
import com.lagou.edu.utils.ClassUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BeanFactory {

    //单例池
    private static Map<String, Object> map = new HashMap<>();

    static {
        InputStream resourceAsStream = BeanFactory.class.getClassLoader().getResourceAsStream("beans.xml");
        //第一步：解析xml，扫描包路径，实例化bean
        SAXReader saxReader = new SAXReader();
        Document document = null;
        try {
            document = saxReader.read(resourceAsStream);
        } catch (DocumentException e) {
            e.printStackTrace();
        }
        Element rootElement = document.getRootElement();
        List<Element> packageList = rootElement.selectNodes("//package");
        String path = packageList.get(0).attributeValue("path");
        List<Class<?>> classes = ClassUtils.getClasses(path);
        for (Class<?> clazz : classes) {
            MyComponent myComponent = clazz.getDeclaredAnnotation(MyComponent.class);
            if (myComponent != null) {
                //取出MyComponent注解的value，作为bean在容器中的key
                String key = myComponent.value();
                Object o = null;
                try {
                    o = clazz.newInstance();
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
                map.put(key, o);
            }
        }

        //第二步：维护对象的依赖关系
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            Object target = entry.getValue();
            Class<? extends Object> clazz = target.getClass();
            Field[] fields = clazz.getDeclaredFields();
            for (Field field : fields) {
                MyAutowired myAutowired = field.getDeclaredAnnotation(MyAutowired.class);
                if (myAutowired != null) {
                    String name = field.getName();
                    Object bean = getBean(name);
                    //强制访问
                    field.setAccessible(true);
                    try {
                        field.set(target, bean);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }

        //第三步：生成目标对象的代理对象
        for (Map.Entry<String, Object> entry : map.entrySet()) {
            String key = entry.getKey();
            Object target = entry.getValue();
            Class<? extends Object> clazz = target.getClass();
            MyTransactional myTransactional = clazz.getDeclaredAnnotation(MyTransactional.class);
            if (myTransactional != null) {
                ProxyFactory proxyFactory = (ProxyFactory) getBean("proxyFactory");
                //使用jdk动态代理
                Object proxy = proxyFactory.getJdkProxy(target);
                map.put(key, proxy);
            }
        }
    }

    //对外提供获取实例对象的接口
    public static Object getBean(String id) {
        return map.get(id);
    }
}
